﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSLib.Parsing.Common;
using PSLib.Parsing.Lua.ObjectModel;

namespace PSLib.Parsing.Lua.ObjectModel
{
    public class ObjectModelProvider
    {
        #region Constructor

        internal ObjectModelProvider()
        {
            this.Scopes = new Dictionary<Guid, Scope>();
            this.ScopesStack = new Stack<Scope>();
            this.GlobalVariables = new Dictionary<string, ValueReference>();
        }

        #endregion

        #region Parser methods

        internal void EnterScope(string name, ElementPosition pos)
        {
            Scope headScope = null;
            if (this.ScopesStack.Count != 0) headScope = this.ScopesStack.Peek();
		    Scope sc = new Scope(name, headScope, this);
            sc.Span.Start = pos;
            this.ScopesStack.Push(sc);
        }
        internal void ExitScope(ElementPosition pos)
        {
            Scope headScope = null;
            if (this.ScopesStack.Count != 0)
            {
                headScope = this.ScopesStack.Pop();
                headScope.Span.End = pos;
            }
        }
        internal Scope CurrentScope
        {
            get
            {
                Scope headScope = null;
                if (this.ScopesStack.Count != 0) headScope = this.ScopesStack.Peek();
                return headScope;
            }
        }

        internal Variable GetGlobalVariable(string key)
        { 
            Variable result = null;
            if (this.GlobalVariables.ContainsKey(key))
            {
                result = new Variable();
                result.Name = key;
                result.SetValue(new ValueReferenceRevision(ElementPosition.GlobalStart, this.GlobalVariables[key]));
            }
            return result;
        }

        #endregion

        #region Public methods

        public Scope GetLocalScope(ElementPosition position)
        {
            if (position == null) return null;
            Scope currentRoot = this.RootScope;
            while (currentRoot.Span.Contains(position))
            {
                bool foundNewRoot = false;
                foreach (var item in currentRoot.ChildScopes)
	            {
                    if (item.Span.Contains(position))
                    {
                        currentRoot = item;
                        foundNewRoot = true;
                        break;
                    }
	            }
                if (!foundNewRoot) break;
            }
            return currentRoot;
        }

        #endregion

        #region Properties
        
        public Scope RootScope
        {
            get { return this.Scopes.Values.FirstOrDefault(); }
        }


        internal Stack<Scope> ScopesStack { get; private set; }
        internal Dictionary<Guid, Scope> Scopes { get; private set; }
        public Dictionary<string, ValueReference> GlobalVariables { get; private set; }

        #endregion
    }
}
